// 运行模块
#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>

namespace ns_runner
{

  using namespace ns_log;
  using namespace ns_util;
  class Runner
  {
  public:
    Runner() {}
    ~Runner() {}

  public:
    // 设置cpu运行时间和内存
    static void SetProcLimit(int _cpu_limit, int _mem_limit)
    {

      struct rlimit cpu_rlimit;
      cpu_rlimit.rlim_max = RLIM_INFINITY;
      cpu_rlimit.rlim_cur = _cpu_limit;
      setrlimit(RLIMIT_CPU, &cpu_rlimit);

      struct rlimit cpu_mlimit;
      cpu_mlimit.rlim_max = RLIM_INFINITY;
      cpu_mlimit.rlim_cur = _mem_limit * 1024; 
      setrlimit(RLIMIT_AS, &cpu_mlimit);
    }
    static int Run(const std::string &file_name, int cpu_limit, int mem_limit)
    {

      const std::string &_execute = PathUtil::Exe(file_name);
      const std::string &_stdin = PathUtil::Stdin(file_name);
      const std::string &_stdout = PathUtil::Stdout(file_name);
      const std::string &_stderr = PathUtil::Stderr(file_name);

      // 打开文件（文件描述符）
      umask(0);
      int _stdout_fd = open(_stdout.c_str(), O_CREAT | O_WRONLY, 0644);
      int _stdin_fd = open(_stdin.c_str(), O_CREAT | O_WRONLY, 0644);
      int _stderr_fd = open(_stderr.c_str(), O_CREAT | O_WRONLY, 0644);

      if (_stdout_fd < 0 || _stdin_fd < 0 || _stderr_fd < 0)
      {
        LOG(ERROR) << "文件打开失败:" << strerror(errno) << "\n";
        exit(-1);
      }

      pid_t pid = fork();
      if (pid < 0)
      {
        LOG(WARNING) << "子进程创建失败" << "\n";
        close(_stderr_fd);
        close(_stdin_fd);
        close(_stderr_fd);
        exit(-1);
      }
      else if (pid == 0)
      {
        // 子进程
        dup2(_stderr_fd, 2);
        dup2(_stdin_fd, 0);
        dup2(_stdout_fd, 1);
      
        execl(_execute.c_str(), "code.exe", NULL);
        LOG(WARNING) << "程序执行失败:" << _execute.c_str() << strerror(errno) << "\n";
        exit(-1);
      }
      else

      {

        // 父进程
        close(_stderr_fd);
        close(_stdin_fd);
        close(_stderr_fd);
        int statues = 0;
        waitpid(pid, &statues, 0);
        return statues & 0x7f;
      }
    }
  };

}